package com.system.core.wechat;

import java.io.IOException;
import java.util.Iterator;
import java.util.TreeMap;

import org.apache.commons.codec.digest.DigestUtils;

import com.alibaba.fastjson.JSONObject;
import com.system.core.utils.HttpUtils;
import com.system.core.wechat.dto.Code2SessionRsp;
import com.system.core.wechat.dto.GetTokenReq;
import com.system.core.wechat.dto.JsSDKSignRsp;
import com.system.core.wechat.dto.Oauth2CodeReq;
import com.system.core.wechat.dto.Oauth2Token;
import com.system.core.wechat.dto.UserPhoneNumberReq;
import com.system.core.wechat.dto.WeChatUser;
import com.system.core.wechat.dto.WechatCode;
import com.system.core.wechat.dto.WechatTicket;
import com.xiaoleilu.hutool.util.RandomUtil;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

@UtilityClass
@Slf4j
public class SecurityUtil {
	
	private final String API_URL_STRING="https://api.weixin.qq.com";
	private final String OPEN_API_URL_STRING="https://open.weixin.qq.com";

	public WechatCode getToken(GetTokenReq req) {
		try {
			String responseBody = HttpUtils.get(API_URL_STRING + "/cgi-bin/token?grant_type=client_credential&appid="+req.getAppid()+"&secret="+req.getSecret());
			WechatCode wechatCode = JSONObject.parseObject(responseBody, WechatCode.class);
			return wechatCode;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public WechatTicket getJsApiTicket(String token) {
		try {
			String responseBody = HttpUtils.get(API_URL_STRING + "/cgi-bin/ticket/getticket?access_token="+token+"&type=jsapi");
			log.debug("[微信]获取ticket结果：{}",responseBody);
			WechatTicket ticket = JSONObject.parseObject(responseBody, WechatTicket.class);
			return ticket;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public JsSDKSignRsp jsSDKSign(String url,String appid,String secret) throws Exception {
		TreeMap<String, Object> params = new TreeMap<>();
		String noncestr = RandomUtil.randomString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",16);
		Long timestamp = System.currentTimeMillis()/1000;
		WechatCode wechatCode = getToken(GetTokenReq.builder()
				.appid(appid)
				.secret(secret)
				.build());
		
		if(wechatCode.getErrcode() != null) {
			throw new Exception(wechatCode.getErrmsg());
		}
		
		WechatTicket wechatTicket = getJsApiTicket(wechatCode.getAccessToken());
		if(wechatTicket.getErrcode() != 0) {
			throw new Exception(wechatTicket.getErrmsg());
		}
		
		params.put("url", url);
		params.put("noncestr", noncestr);
		params.put("timestamp", timestamp);
		params.put("jsapi_ticket", wechatTicket.getTicket());
		StringBuilder urls = new StringBuilder();
		
		for(Iterator<String> itor = params.keySet().iterator();itor.hasNext();) {
			String key = itor.next();
			urls.append(key+"=");
			urls.append(params.get(key));
			if(itor.hasNext())
				urls.append("&");
		}
		
		log.debug("[微信]签名原文：{}",urls);
		
		String signstr = DigestUtils.sha1Hex(urls.toString());
		
		return JsSDKSignRsp.builder()
				.signature(signstr)
				.jsapiTicket(wechatTicket.getTicket())
				.nonceStr(noncestr)
				.timestamp(timestamp)
				.url(url)
				.build();
	}
	
	public static void main(String[] args) throws Exception {
		System.out.println(SecurityUtil.jsSDKSign(
				"https://farming.tst.cqtancheng.com/gisView/landMini/preview", 
				"wx4592813f5a12470d",
				"083cd2d53fac205ae6117c165d82f15d"
				));
	}
	
	public String getOauth2Code(Oauth2CodeReq oauth2CodeReq) {
		return OPEN_API_URL_STRING + "/connect/qrconnect?appid="+oauth2CodeReq.getAppid()+
				"&redirect_uri="+oauth2CodeReq.getRedirectUri()+
				"&response_type=code&scope="+oauth2CodeReq.getScope()+
				"&state="+oauth2CodeReq.getState()+"#wechat_redirect";
	}
	public Oauth2Token getOauth2AccessToken(String appid,String secret,String code) {
		try {
			String responseBody = HttpUtils.get(API_URL_STRING + "/sns/oauth2/access_token?appid="+appid+"&secret="+secret+"&code="+code+"&grant_type=authorization_code");
			log.debug("[微信]Oauth2获取Token结果：{}",responseBody);
			Oauth2Token oauth2Token = JSONObject.parseObject(responseBody, Oauth2Token.class);
			return oauth2Token;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	public Oauth2Token refreshOauth2AccessToken(String appid,String refreshToken) {
		try {
			String responseBody = HttpUtils.get(API_URL_STRING + "/sns/oauth2/refresh_token?appid="+appid+"&grant_type=refresh_token&refresh_token="+refreshToken);
			log.debug("[微信]Oauth2获取refresh_token结果：{}",responseBody);
			Oauth2Token oauth2Token = JSONObject.parseObject(responseBody, Oauth2Token.class);
			return oauth2Token;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	public WeChatUser wechatUserInfo(String openid,String accessToken) {
		try {
			String responseBody = HttpUtils.get(API_URL_STRING + "/sns/userinfo?access_token="+accessToken+"&openid="+openid);
			log.debug("[微信]Oauth2获取userinfo结果：{}",responseBody);
			WeChatUser weChatUser = JSONObject.parseObject(responseBody, WeChatUser.class);
			return weChatUser;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * @see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
	 * @param jscode
	 * @return
	 */
	public Code2SessionRsp code2Session(String appid,String secret,String jscode) {
		try {
			String resultjson = HttpUtils.get(API_URL_STRING+"/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+jscode+"&grant_type=authorization_code");
			log.debug("[微信]jscode2session返回结果：{}",resultjson);
			return JSONObject.parseObject(resultjson, Code2SessionRsp.class);
		} catch (IOException e) {
			e.printStackTrace();
			return Code2SessionRsp.builder().errcode(-1).errmsg(e.getMessage()).build();
		}
	}
	
	public String getUserPhoneNumber(UserPhoneNumberReq req) {
		try {
			String responseStr = HttpUtils.post(API_URL_STRING+"/wxa/business/getuserphonenumber?access_token="+req.getAccessToken(), "{\"code\":\""+req.getCode()+"\"}");
			return responseStr;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
}
